#********************************************************************************************************
#                                               uC/OS-II
#                                         The Real-Time Kernel
#
#                          (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
#                                          All Rights Reserved
#
#
#                                       80x86/80x88 Specific code
#                                          LARGE MEMORY MODEL
#
#                                           Borland C/C++ V4.51
#                                       (IBM/PC Compatible Target)
#
# File         : OS_CPU_A.ASM
# By           : Jean J. Labrosse
#********************************************************************************************************

#********************************************************************************************************
#                                    PUBLIC and EXTERNAL REFERENCES
#********************************************************************************************************

            .global OSTickISR
            .global OSStartHighRdy
            .global OSCtxSw
            .global OSIntCtxSw

            .extern  OSIntExit
            .extern  OSTimeTick
            .extern  OSTaskSwHook

            .extern  OSIntNesting
            .extern  OSTickDOSCtr
            .extern  OSPrioHighRdy
            .extern  OSPrioCur
            .extern  OSRunning
            .extern  OSTCBCur
            .extern  OSTCBHighRdy

#*********************************************************************************************************
#                                          START MULTITASKING
#                                       void OSStartHighRdy(void)
#
# The stack frame is assumed to look as follows:
#
# OSTCBHighRdy->OSTCBStkPtr --> DS                               (Low memory)
#                               ES
#                               DI
#                               SI
#                               BP
#                               SP
#                               BX
#                               DX
#                               CX
#                               AX
#                               OFFSET  of task code address
#                               SEGMENT of task code address
#                               Flags to load in PSW
#                               OFFSET  of task code address
#                               SEGMENT of task code address
#                               OFFSET  of 'pdata'
#                               SEGMENT of 'pdata'               (High memory)
#
# Note : OSStartHighRdy() MUST:
#           a) Call OSTaskSwHook() then,
#           b) Set OSRunning to TRUE,
#           c) Switch to the highest priority task.
#           1.调用Call OSTaskSwHook()
#           2.设置系统运行为真
#           3.切换到更高级别任务
#
#*********************************************************************************************************

OSStartHighRdy:
	bl OSTaskSwHook
	
	ldr     R4, =OSRunning         
	mov     R5, #1
	strb    R5, [R4]
        
@ SP = OSTCBHighRdy->OSTCBStkPtr                             
	ldr     R4, =OSTCBHighRdy
	ldr     R5, [R4]
	ldr     sp, [R5]
	
	ldmia sp!,{r0}
	msr cPSR,r0
	ldmia sp!, {r0-r12,r14,pc}
#*********************************************************************************************************
#                                PERFORM A CONTEXT SWITCH (From task level)
#                                           void OSCtxSw(void)
#
# Note(s): 1) Upon entry,
#             OSTCBCur     points to the OS_TCB of the task to suspend
#             OSTCBHighRdy points to the OS_TCB of the task to resume
#
#          2) The stack frame of the task to suspend looks as follows:
#
#                 SP -> OFFSET  of task to suspend    (Low memory)
#                       SEGMENT of task to suspend
#                       PSW     of task to suspend    (High memory)
#
#          3) The stack frame of the task to resume looks as follows:
#
#                 OSTCBHighRdy->OSTCBStkPtr --> DS                               (Low memory)
#                                               ES
#                                               DI
#                                               SI
#                                               BP
#                                               SP
#                                               BX
#                                               DX
#                                               CX
#                                               AX
#                                               OFFSET  of task code address
#                                               SEGMENT of task code address
#                                               Flags to load in PSW             (High memory)
#*********************************************************************************************************

OSCtxSw:
	
@ OSTCBCur->OSTCBStkPtr  = SP
	ldr r4, =OSTCBCur
	ldr r5, [r4]
	str sp, [r5]
	
	bl OSTaskSwHook
	
	
@ OSTCBCur = OSTCBHighRdy
	ldr r4, =OSTCBCur
	ldr r5, =OSTCBHighRdy
	ldr r6,[r5]
	str r6, [r4]

@ OSPrioCur = OSPrioHighRdy
	ldr r4, =OSPrioCur
	ldr r5, =OSPrioHighRdy
	ldrb r6,[r5]
	strb r6, [r4]
@ SP = OSTCBHighRdy->OSTCBStkPtr
	ldr     R4, =OSTCBHighRdy
	ldr     R5, [R4]
	ldr     sp, [R5]
	
	ldmia sp!,{r0}
	msr cPSR,r0
	ldmia sp!, {r0-r12,r14,pc}
#*********************************************************************************************************
#                                PERFORM A CONTEXT SWITCH (From an ISR)
#                                        void OSIntCtxSw(void)
#
# Note(s): 1) Upon entry,
#             OSTCBCur     points to the OS_TCB of the task to suspend
#             OSTCBHighRdy points to the OS_TCB of the task to resume
#
#          2) The stack frame of the task to suspend looks as follows:
#
#             OSTCBCur->OSTCBStkPtr ------>  DS                              (Low memory)
#                                            ES
#                                            DI
#                                            SI
#                                            BP
#                                            SP
#                                            BX
#                                            DX
#                                            CX
#                                            AX
#                                            OFFSET  of task code address
#                                            SEGMENT of task code address
#                                            Flags to load in PSW            (High memory)
#
#
#          3) The stack frame of the task to resume looks as follows:
#
#             OSTCBHighRdy->OSTCBStkPtr --> DS                               (Low memory)
#                                           ES
#                                           DI
#                                           SI
#                                           BP
#                                           SP
#                                           BX
#                                           DX
#                                           CX
#                                           AX
#                                           OFFSET  of task code address
#                                           SEGMENT of task code address
#                                           Flags to load in PSW             (High memory)
#*********************************************************************************************************

OSIntCtxSw:

	bl OSTaskSwHook
	
	
@ OSTCBCur = OSTCBHighRdy
	ldr r4, =OSTCBCur
	ldr r5, =OSTCBHighRdy
	ldr r6,[r5]
	str r6, [r4]

@ OSPrioCur = OSPrioHighRdy
	ldr r4, =OSPrioCur
	ldr r5, =OSPrioHighRdy
	ldrb r6,[r5]
	strb r6, [r4]
@ SP = OSTCBHighRdy->OSTCBStkPtr
	ldr     R4, =OSTCBHighRdy
	ldr     R5, [R4]
	ldr     sp, [R5]
	
	ldmia sp!,{r0}
	msr cPSR,r0
	ldmia sp!, {r0-r12,r14,pc}
	
#*********************************************************************************************************
#                                            HANDLE TICK ISR
#
# Description: This function is called 199.99 times per second or, 11 times faster than the normal DOS
#              tick rate of 18.20648 Hz.  Thus every 11th time, the normal DOS tick handler is called.
#              This is called chaining.  10 times out of 11, however, the interrupt controller on the PC
#              must be cleared to allow for the next interrupt.
#
# Arguments  : none
#
# Returns    : none
#
# Note(s)    : The following C-like pseudo-code describe the operation being performed in the code below.
#
#              Save all registers on the current task's stack#
#              OSIntNesting++#
#              if (OSIntNesting == 1) {
#                 OSTCBCur->OSTCBStkPtr = SS:SP
#              }
#              OSTickDOSCtr--#
#              if (OSTickDOSCtr == 0) {
#                  OSTickDOSCtr = 11#
#                  INT 81H#               Chain into DOS every 54.925 mS
#                                         (Interrupt will be cleared by DOS)
#              } else {
#                  Send EOI to PIC#       Clear tick interrupt by sending an End-Of-Interrupt to the 8259
#                                         PIC (Priority Interrupt Controller)
#              }
#              OSTimeTick()#              Notify uC/OS-II that a tick has occured
#              OSIntExit()#               Notify uC/OS-II about end of ISR
#              Restore all registers that were save on the current task's stack#
#              Return from Interrupt#
#*********************************************************************************************************
#
OSTickISR:

	
	ldr r4, =OSIntNesting
	ldr r5, =0
	ldrb r5,[r4]
	add r5,r5,#1
	strb r5,[r4]                      @Notify uC/OS-II of ISR

	cmp    r5, #1	 @if (OSIntNesting == 1)
        bne _OSTickISR1         
@ OSTCBCur->OSTCBStkPtr  = SP
	ldr r4, =OSTCBCur
	ldr r5, [r4]
	str sp, [r5]
_OSTickISR1:
	ldr r5,=0x10011000
	add r5,r5,#0x0C
	str r4, [r5]

	bl OSTimeTick           @Process system tick

	bl OSIntExit            @ Notify uC/OS-II of end of ISR
            
	ldmia sp!,{r0}
	msr cPSR,r0
	ldmia sp!, {r0-r12,r14,pc}
